#pragma once 

#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdlib.h>
#include <cstring>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
#include "Log.hpp"
#include <unistd.h>

#define BACKLOG 5

//将Tcp端以单例模式的形式实现
class TcpServer
{
  private:
    int port;
    int listen_sock;
    static TcpServer* svr;
  private:
    TcpServer(int _port)
      :port(_port),listen_sock(-1)
    {}
    
    TcpServer(const TcpServer& s){}

  public:
    static TcpServer* getinstance(int _port)
    {
        //直接使用这种方式进行初始化，此方式创建的锁不需要释放
        static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; 
        if (svr == nullptr) 
        { //此时对象并没有存在
            pthread_mutex_lock(&lock);
            if (svr == nullptr)
            {
                svr = new TcpServer(_port);
                svr->InitServer(); //初始化一下
            }
            pthread_mutex_unlock(&lock);
        }

        return svr;
    }

    void InitServer()
    {
        Socket();
        Bind();
        Listen();
        LOG(INFO , "tcp_server init ... success!");
    }

    void Socket() //创建套接字
    {
        listen_sock = socket(AF_INET , SOCK_STREAM , 0);
        if (listen_sock < 0)
        {//创建套接字失败了
          LOG(FATAL , "socket error!");
          exit(1); //终止进程
        }
        //下面的函数时用来复用当前端口的，为了防止连接崩溃时端口因为未被释放而导致下一个绑定失败
        int opt = 1;
        setsockopt(listen_sock , SOL_SOCKET , SO_REUSEADDR , &opt , sizeof(opt));
        LOG(INFO , "create socket ... success!");
    }

    void Bind() //绑定
    {
        struct sockaddr_in local;
        memset (&local , 0 , sizeof local);
        local.sin_family = AF_INET;
        local.sin_port = htons(port);
        local.sin_addr.s_addr = INADDR_ANY;
        if (bind(listen_sock , (struct sockaddr*)&local , sizeof(local)) < 0)
        {
          LOG(FATAL , "bind error!");
          exit(2);
        }
        LOG(INFO , "bind socket ... success!");
    }

    void Listen() //监听
    {
        if (listen(listen_sock , BACKLOG) < 0)
        {
          LOG(FATAL , "listen error!");
          exit(3);
        }
        LOG(INFO , "listen socket ... success!");
    }
    
    int Sock()
    {
      return listen_sock;
    }

    ~TcpServer()  
    {
      if (listen_sock >= 0) close(listen_sock);
    }
};

TcpServer* TcpServer::svr = nullptr;

